package screenpac.features;

import java.awt.Color;
import java.util.ArrayList;
import java.util.LinkedList;

import screenpac.model.GameState;
import screenpac.model.GameStateInterface;
import screenpac.model.GhostState;
import screenpac.model.Node;

public class GaiAStarSearch {
	
	
	public LinkedList<Node> findPath(Node startNode, Node targetNode, GameStateInterface gs) {
		
		//Declare open and close Lists
		PriorityList openList = new PriorityList();
		LinkedList<Node> closedList = new LinkedList<Node>();
		
		//Setup starting values
		startNode.costG = 0;
		startNode.costH = startNode.getHCost(targetNode);
		startNode.parentNode = null;
		openList.add(startNode);
		
		while(!openList.isEmpty()) {
			Node node = (Node)openList.removeFirst();
			if(node == targetNode) {
				return constructPath(targetNode);
			}
			
			ArrayList<Node> adj = node.adj;
			
			for(Node n: adj) {
				//n.parentNode = null; // RESET?
				boolean isOpen = openList.contains(n);
				boolean isClosed = closedList.contains(n);
				float costG = node.costG + node.getCost(n, gs) + getPenalty(n, gs);
				//System.out.println("CostG: " + costG);
				
				if( (!isOpen && !isClosed) || costG < n.costG ) {
					n.parentNode = node;
					n.costG = costG;
					n.costH = n.getHCost(targetNode);
					if(isClosed){
						closedList.remove(n);
					}
					if(!isOpen) {
						openList.add(n);
					}
				}
			}
			closedList.add(node);
		}
		//No path found
		return null;
	}
	
	public float getPenalty(Node node, GameStateInterface gs) {
		if (gs.getPacman().dangerLevel(gs) < 40) { // 35
			// There is a near Ghost! Check where
			for (GhostState ghost : gs.getGhosts()) {
				if (gs.getMaze().dist(ghost.current, node) < 20) { // 8
					if (ghost.edibleTime > 10) {
						return 0.0f;
					} else {
						// Penalize with a high value invers to the distance
						float value = (1.0f / gs.getMaze().dist(ghost.current, node)) * 400000.0f;
						/* DEBUG
						System.out.println("Value: " + value);
						if(value > 17000) {
							node.col = Color.red;
						} else if(value > 13000) {
							node.col = Color.orange;
						} else if(value > 10000) {
							node.col = Color.yellow;
						}
						*/
						return value;
					}
				}
			}
		}
		return 0.0f;
	}
	
	public static class PriorityList extends LinkedList {
		public boolean add(Comparable object) {
			for(int i=0; i<size(); i++) {
				if(object.compareTo(get(i)) <= 0) {
					add(i, object);
					return true;
				}
			}
			addLast(object);
			return true;
		}
	}
	
	/**
	 * Construct A* Path
	 * @param node
	 * @return
	 */
	public LinkedList<Node> constructPath(Node node) {
		LinkedList<Node> path = new LinkedList<Node>();
		while(node.parentNode != null) {
			path.addFirst(node);
			node = node.parentNode;
		}
		return path;
	}
	
	
	
	
	
}
